iT邦幫忙

2022 iThome 鐵人賽

DAY 23
0
Software Development

你知道Go是什麼嗎?系列 第 23

Day23 - WebSocket - Golang

  • 分享至 

  • xImage
  •  

今天來介紹通訊協定WebSocket吧,最近都會想主題想一陣子才知道要寫什麼,各種前輩的文章翻來翻去,好就介紹這個吧ˊˇˋ

WebSocket

先看一下wiki介紹

WebSocket是一種網路傳輸協定,可在單個TCP連接上進行全雙工通訊,位於OSI模型的應用層。

WebSocket使得客戶端和伺服器之間的資料交換變得更加簡單,允許伺服器端主動向客戶端推播資料。在WebSocket中,只需要完成一次交握,兩者之間就可以建立永續性的連接,並進行雙向資料傳輸。

發展

http中,client請求server回應,連線就會中斷了,若是server有更新要傳回,也只能等client發出請求才能回應。若是傳輸頻率很高,就必須讓client不斷發出請求,在效能上的表現並不好,也不能真正取得即時訊息。

而能夠即時通訊的WebSocket協定就在2008年因應而生。

通訊方式

WebSocket是雙向通訊模式,在client送出handshake(握手)建立連線後,即開始雙向模式互動,clientserver端都能隨時將資料傳給對方,直到disconnect為止。

比較

我們比較一下WebSockethttp兩種協定有什麼相似之處與相異之處

相同處:

  • 基於TCP的一種傳輸協定
  • OSI Layer7協定

相異處:

  • Http為單向通訊協議;Websocket是雙向通訊。
  • Httpclientserver發起連線;WebSocketHandshake建立連線。
  • Http為短連線,請求結束後會釋放連線;WebSocket建立連線後伺服器會持續監聽請求,不用每次重新連線。

Go實現WebSocket

Go語言標準套件裡面沒有提供對WebSocket的支援,這邊使用由Gorilla團隊製作的WebSocket套件,gorilla/websocket

get與import

go get github.com/gorilla/websocket

import(
    "github.com/gorilla/websocket"
)

建立server端

package main

import (
	"log"
	"net/http"
	"fmt"
	"github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{}

func socketHandler(w http.ResponseWriter, r *http.Request) {
    // Upgrade our raw HTTP connection to a websocket based one
    conn, err := upgrader.Upgrade(w, r, nil)
    if err != nil {
        log.Print("Error during connection upgradation:", err)
        return
    }
    defer func() {
        log.Println("disconnect !!")
        conn.Close()
    }()

    // The event loop
    for {
        messageType, message, err := conn.ReadMessage()
        if err != nil {
            log.Println("Error during message reading:", err)
            break
        }
        log.Printf("Received: %s", message)
        err = conn.WriteMessage(messageType, message)
        if err != nil {
            log.Println("Error during message writing:", err)
            break
        }
    }
}

func home(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Index Page")
}

func main() {
	http.HandleFunc("/socket", socketHandler)
    log.Println("server start at :8080")
	http.HandleFunc("/", home)
	log.Fatal(http.ListenAndServe(":8080", nil))
}

寫完後可以將伺服器執行起來

練立client端

這邊客戶端的功能是每隔一秒會往伺服器傳一次"WebSocket Success!"

package main

import (
	"log"
	"time"

	"github.com/gorilla/websocket"
)

func main() {
	conn, _, err := websocket.DefaultDialer.Dial("ws://127.0.0.1:8080/socket", nil)
	if err != nil {
		log.Fatal("dial:", err)
	}
	defer conn.Close()
	for {
		time.Sleep(time.Second)
		err = conn.WriteMessage(websocket.TextMessage, []byte("WebSocket Success!"))
		if err != nil {
			log.Println(err)
			return
		}
		_, msg, err := conn.ReadMessage()
		if err != nil {
			log.Println("read:", err)
			return
		}
		log.Printf("receive: %s\n", msg)
	}
}

客戶端這邊顯示

output:

2022/10/08 15:54:04 receive: WebSocket Success!
2022/10/08 15:54:05 receive: WebSocket Success!
.
.
.

伺服器端顯示

output:

2022/10/08 15:54:04 Received: WebSocket Success!
2022/10/08 15:54:05 Received: WebSocket Success!
.
.
.

一份WebSocket測試完成了,這邊是最基礎的使用法


參考資料

慢聊Go之GoLang中使用Gorilla Websocket|Go主题月
https://juejin.cn/post/6946952376825675812

Golang 如何建構一個 websocket server
https://ithelp.ithome.com.tw/articles/10208531

WebSocket
https://ithelp.ithome.com.tw/articles/10249282

WebSocket協議入門介紹
https://iter01.com/420761.html


上一篇
Day22 - Redis - Golang
下一篇
Day24 - Reflection - Golang
系列文
你知道Go是什麼嗎?30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言